package dletc.lock;

/**
 * 线程同步：如何解决线程的安全问题：
 *  1.synchronized 隐形锁
 *  2.reentrantLock 显性锁
 * <p>
 * 1.多线程可能会出现的问题： 错误数据（错票、重复）
 * <p>
 * 2.产生线程安全问题的原因：
 * <p>
 * 当一个线程操作的时候，还没来得及结束，另一个线程也参与进来了，导致了同时修改了同一个数据。
 * <p>
 * 3.线程安全问题的三个必要条件：
 * 条件1： 多线程并发
 * 条件2： 有共享数据
 * 条件3： 共享数据有被修改的行为
 * <p>
 * 4. 如何解决：多线程同步机制
 * <p>
 * 什么是线程同步机制：让线程排队执行(队列)，不让他并发(concurrent)执行
 * 优点：数据安全
 * 缺点：效率低
 * 方法：利用同步代码块的方式解决
 * 语法：
 * 第一种：
 * synchronized(同步监听器/线程锁){
 * 需要配同步的代码[操作共享数据的代码]
 * }
 * <p>
 * 第二种：在实例方法上直接使用synchronized关键字（不灵活）
 * 表示共享对象一定是this
 * 并且同步代码是整个方法体
 * <p>
 * 第三种：在静态方法上使用synchronized关键字（很少）
 * 表示找类锁，保证静态变量的安全
 * 类锁永远只有1把，对象锁：每个对象都有一把锁。
 * 创建100个对象，有100把对象锁，但可能只有一把类锁。
 * <p>
 * 重点：**()线程锁写什么？**
 * 那要看你想让哪些线程同步：
 * 假设t1 t2 t3 t4 t5 有五个线程，你只希望t1 t2 t3排队，
 * t4 t5 不需要排队，怎么办？ 需要在()中写一个t1 t2 t3的共享对象，
 * 而这个对象对t4 t5 不是共享的。
 * （最终写的是想让谁排队，就写谁的共享对象，一般写this（谁共享this代表的对象，谁排队）
 * Object对象（在属性，不能是局部变量） ，写一个"abc"也行，因为在字符串常量池中，但会让所有线程排队。）
 *
 * synchronized使用方式：
 *  1.synchronized(){} 代码块形式
 *  2.synchronized作为关键字
 */
public class Demo08 {

    public static void main(String[] args) {

        MyThread8 mt8 = new MyThread8();
        MyThread8 mt9 = new MyThread8();

        mt8.setName("线程1");
        mt9.setName("线程2");

        mt8.start();
        mt9.start();

    }

}

class MyThread8 extends Thread {

    //票数  需要加static 成为公共的 不然会变成3套票 因为new了三个对象 每一个对象都有自己的实例变量。
    static int num = 100;

    @Override
    public void run() {
        //同步代码块 synchronized(){}   (线程锁)小括号里 可以是任意的对象。
        synchronized ("num") {
            for (int i = num; num > 0; num--) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "卖票-----" + num);
            }
        }

    }
}
